#include "FieldItem.h"
#include "formatitem.h"
#include "qvariant.h"

using namespace std;

FieldItem::FieldItem(Format *format,
                     FEFieldNode *node,
                     FieldItem* parent)
    : format_(format), parent_(parent) {

    node_ = *node;

    if (!format) {
        atom_ = false;
        return;
    }

    if (node_.translate_type == FEFieldNode::ToText) {
        mem_buffer_ = newMemoryFEBuffer(format_->getFieldName(node_.field).toStdString().c_str(),
                                        (FEBuffer *)(node_.range.buffer),
                                        node_.range.bit_offset,
                                        node_.range.bit_len,
                                        node_.translation.t.ptr,
                                        node_.translation.t.len);
    }

    atom_ = format->isAtomField(node_.field);
}

FieldItem::~FieldItem()
{
    FieldItem *child;
    foreach (child, children_) {
        delete child;
    }
    children_.clear();

    if (mem_buffer_) {
        deleteFEBuffer(mem_buffer_);
        mem_buffer_ = nullptr;
    }

    if (node_.context && node_.free) {
        node_.free(node_.context);
        node_.context = nullptr;
    }
}

void FieldItem::appendChild(FieldItem* child) {
    if (!children_.empty()) {
        auto last = children_.back();
        last->next_ = child;
        child->pre_ = last;
    }

    children_.append(child);
}

FieldItem* FieldItem::child(int row) {
//    qDebug() << "child" << data(0);
    dessect();
    if (row < 0 || row >= children_.size())
        return nullptr;
    return children_.at(row);
}

int FieldItem::childCount() const {
//    qDebug() << "childCount" << data(0);
    const_cast<FieldItem*>(this)->dessect();
    return children_.size();
}

int FieldItem::columnCount() const {
//    qDebug() << "columnCount" << data(0);
    return 1; // 只有一列数据
}

QVariant FieldItem::data(int column) const {
    if (!format_) return QString("root");

//    qDebug() << "data" << format_->getFieldName(id_);

    if (column == 0) {
        auto display = getDisplayMask() + getDisplayName();
        auto value = getDisplayValue();
        if(!value.isEmpty()) {
            display.append(": ");
            display.append(value);
        }
        return display;
    }

    return QVariant();
}

int FieldItem::row() const {
//    qDebug() << "row" << data(0);
    const_cast<FieldItem*>(this)->dessect();
    if (parent_)
        return parent_->children_.indexOf(const_cast<FieldItem*>(this));
    return 0;
}

FieldItem* FieldItem::parent() {
//    qDebug() << "parent" << data(0);
    return parent_;
}

FERange FieldItem::range()
{
    return node_.range;
}

void FieldItem::constructChildren(FEList *nodes, uint8_t depth) {
    auto node = (FEFieldNode *)getNextFEUnit(nodes);
    FieldItem *item = nullptr;
    while (node) {
        if (node->depth == depth) {
            //本层节点
            item = new FieldItem(format_, node, this);
            appendChild(item);
        } else if (node->depth > depth){
            //下层节点
            putbackFEUnit(nodes);
            item->constructChildren(nodes, node->depth);
        } else {
            //上层节点
            putbackFEUnit(nodes);
            break;
        }

        node = (FEFieldNode *)getNextFEUnit(nodes);
    }

    //dessect immediately
    foreach(item, children_) {
        if (item->node_.field->immediate)
            item->dessect();
    }

    //解析完成后更新区间
    if (!mem_buffer_) {
        if (node_.range.bit_len == -1) {
            auto last = children_.back();
            if (last->node_.range.bit_offset >= 0 && last->node_.range.bit_len >= 0)
                node_.range.bit_len = last->node_.range.bit_offset + last->node_.range.bit_len - node_.range.bit_offset;
        }
    }
}

void FieldItem::dessect()
{
    //无法解析或者已经解析过，无需处理
    if (atom_ || !children_.empty()) return;

    // 准备区间
    FERange range;
    if (mem_buffer_) {
        //新buffer
        range.buffer = mem_buffer_;
        range.bit_offset = 0;
        range.bit_len = mem_buffer_->data_len << 3;
    } else {
        //子区间
        range = node_.range;
        if (range.bit_offset == -1) {
            //如果节点长度不明确，根据位置更新
            if (pre_) {
                //紧跟兄节点
                if (pre_->node_.range.bit_offset >= 0 && pre_->node_.range.bit_len >= 0) {
                    node_.range.bit_offset = pre_->node_.range.bit_offset + pre_->node_.range.bit_len;
                    range.bit_offset = node_.range.bit_offset;
                } else
                    return;
            } else {
                //对齐父节点
                if (parent_->node_.range.bit_offset >= 0) {
                    node_.range.bit_offset = parent_->node_.range.bit_offset;
                    range.bit_offset = node_.range.bit_offset;
                } else
                    return;
            }
        }

        if (range.bit_len == -1) {
            if (next_ && next_->node_.range.bit_offset >= 0) //对齐弟节点
                range.bit_len = next_->node_.range.bit_offset - range.bit_offset;
            else if (parent_->node_.range.bit_offset >= 0 && parent_->node_.range.bit_len >= 0) //对齐父节点
                range.bit_len = parent_->node_.range.bit_offset + parent_->node_.range.bit_len - range.bit_offset;
            else
                return;
        }
    }

    //启动解析
    FEList nodes;
    initFEList(&nodes, sizeof(FEFieldNode));
    format_->dessectField(range, node_.context, node_.field, &nodes);

    //根据解析结果构造子树
    constructChildren(&nodes, 0);
    clearFEList(&nodes);
}

QString FieldItem::getDisplayMask() const
{
    if (node_.range.bit_len & 0x7 || node_.range.bit_offset & 0x7) {
        return QString("*");
    }

    return QString();
}

QString FieldItem::getDisplayName() const
{
    auto name = format_->getFieldName(node_.field);
    if (name.isEmpty()) name = "unnamed";
    if (node_.index1 != -1) name.append(QString("[%1]").arg(node_.index1));
    if (node_.index2 != -1) name.append(QString("[%1]").arg(node_.index2));
    if (node_.index3 != -1) name.append(QString("[%1]").arg(node_.index3));
    return name;
}

QString FieldItem::getDisplayValue() const
{
    auto value = format_->getNodeValue(node_);
    if (value.isEmpty()) {
        if (node_.translate_type == FEFieldNode::ToFloat) {
            value = QString("%1").arg(node_.translation.d);
        } else if (node_.translate_type == FEFieldNode::ToInt) {
            value = QString("%1").arg(node_.translation.i);
        } else if (node_.translate_type == FEFieldNode::ToUInt) {
            value = QString("%1").arg(node_.translation.ui);
        }
    }
    return value;
}
